package presentation;

import java.io.IOException;
import java.net.UnknownHostException;
import java.util.Scanner;
import java.util.Vector;
import domain.WsepConnection;
import domain.items.Item;
import domain.items.PostPacket;
import domain.items.ThreadPacket;
import domain.items.TopicPacket;
import domain.users.Guest;
import domain.users.Member;
import interfaces.UI;
import interfaces.UserConnection;

/**
 * no GUI yet, so we'll use this class for running and testing the program.
 * @author awarmanX
 *
 */
public class WsepUI implements UI{

	Scanner in;

/**
 * once the surfer started the program he has his own Connection instance, through which all the info
 * between the surfer and the system will be passed.
 */
	private UserConnection _connection;

/**
 * constructor
 */
	public WsepUI() {
		try {
			this._connection = new WsepConnection(new Guest());

		} catch (IOException e) {
			// TODO Auto-generated catch block
		}
	}


/**
 * the Main program needs this method to have a starting page. the starting page should be some kind of
 * a menu with basic options - login as a member, login as a guest, etc...
 * @throws IOException
 */
	public void showWelcomePage() throws IOException {
		TopicPacket rootTopic = this._connection.getRootTopic();
		this.showItem(rootTopic);

	}

/**
 * show some kind of "successful login" message before moving on
 * @param userName
 * @param password
 */
	private void showLoginSuccess(String userName) {
		// TODO Auto-generated method stub
		System.out.println("You are now logged in as "+userName);
	}




/**
 * show a failure message\menu
 */
	private void showLoginFailed() {
		// TODO Auto-generated method stub

	}


	private void showItem(Item item) {

		this._connection.setCurrentlyViewedItem(item);

		System.out.println("**************** WSEP FORUM *******************************************");

		System.out.println("*** Enter '-1' to go one step back ***");
		System.out.println("*** Enter '-2' to go to root topic ***");

		if (this._connection.getCurrentlyViewedItem() != null) {
			System.out.println("Your location is: "+this._connection.getCurrentlyViewedItem().getName());
		}

		if (item instanceof TopicPacket){
			this.showTopic((TopicPacket)item);
		}
		else if (item instanceof ThreadPacket){
			this.showThread((ThreadPacket)item);
		}
		else{
			this.showPost((PostPacket)item);
		}
		waitForInput(item);
	}

	private void waitForInput(Item item) {

		System.out.print("type your choice (or 0 for other options): ");
		// reading the input...
		int choice = this.readNumber();

		// option for stepping back
		//if ((choice == -1) && (this._connection.getCurrentlyViewedItem().getFather() == null)){
		//	this.waitForInput(item);
		//}
		if (choice == -1) {
			this.showItem(this._connection.getFather());
		}


		if (choice ==-2){
			this.showItem(this._connection.getRootTopic());
		}

		if (choice == 0){
			this.showSpecialMenu();
			this.showItem(item);

		if (choice < -2) {
			this.waitForInput(item);
		}

		}else{
			Item chosenItem = this._connection.getItem(choice);
			this._connection.setCurrentlyViewedItem(chosenItem);
			this.showItem(chosenItem);
		}
	}


	private boolean showSpecialMenu() {
		System.out.println("Type the needed option (type \"0\" to exit menu):");
		int userRank = this._connection.getUserRank();
		if (userRank == 0){
			System.out.println("(1) Login");
			System.out.println("(2) Register");
			System.out.println("(3) Search");
		}
		if (userRank >= 1){
			if (this._connection.getCurrentlyViewedItem() instanceof TopicPacket) {
				System.out.println("(1) Add New Message in a new Thread");
				System.out.println("(3) Search");
			}
			else{
			System.out.println("(1) Reply To A Message");
			System.out.println("(2) Modify Message");
			System.out.println("(3) Search");
			}
		}
		if (userRank >= 2){
			System.out.println("(4) Delete Message");
		}
		if (userRank == 3) {
			System.out.println("(5) Demote User");
			System.out.println("(6) Promote User");
			System.out.println("(7) Delete User");
			System.out.println("(8) Add Topic");
			System.out.println("(9) Modify Topic");
		}
		int choice = this.readNumber();
		boolean cancel = false;
		if (choice == 0)
			cancel = true;
		/*
		 * the following code is for the case it's a Guest!
		 */
		if (userRank == 0){
			if (choice == 1){
				showLoginPage();
			}
			else if (choice == 2){
				showRegistrationPage();
			}
			else if (choice == 3){
				showSerachMenu();
			}
		}

		/*
		 * the following code is for the case it's a registered Member of the forum!
		 */
		else
			if (userRank >= 1){
			if (choice == 3){
				showSerachMenu();
			}
			//for the case he is inside a Thread!
			else if (this._connection.getCurrentlyViewedItem() instanceof ThreadPacket){
				if (choice == 1){
					handleAddMessage();// for the case he chose to add a new message
				}else if (choice == 2){
					System.err.println("Canceled: you must be in a clear view on a certain Post in order to modify it!");
				}
			} //for the case he is inside a Topic!
		       else if (this._connection.getCurrentlyViewedItem() instanceof TopicPacket
		    	   && (choice == 1)){
		    	   handleAddANewThread(); // for the case he chose to add a new Thread (+ first mandatory Message)

		       }else if (this._connection.getCurrentlyViewedItem() instanceof PostPacket
		    	   && (choice == 2)){
		    	   handleModifiyAMessage();// for the case he chose to modify a message
		       }
			}


		/*
		 * the following code is for the case it's a Moderator of the forum!
		 */
			if (userRank >= 2){
				if (choice == 4){ //for Deleting A Message!!
					 if (!(this._connection.getCurrentlyViewedItem() instanceof PostPacket)){
						 System.err.println("Canceled: you must be in a clear view on a certain Post in order to delete it!");
					}
					 else{
						 handleDeletePost();
						}
				}
			}

			if (userRank == 3){
				if (choice == 5){ // DEMOTE RANKING!!!
						handleDemoteUser();
				}else if (choice == 6){// PROMOTE RANKING!!!
					handlePromoteUser();
				}
				if (choice == 7){
					handleDeleteUser();
				}

			}

	return cancel;
}


	private void showSerachMenu() {
		System.out.println("(1) search By Author");
		System.out.println("(2) search By Date");
		System.out.println("(3) search By Content");

		int choice = this.readNumber();
		if (choice == 0)
			this.showItem(this._connection.getCurrentlyViewedItem());
		else if (choice == 1){
			handleSearchByAuthor();
		}
		else if (choice == 2){
			handleSearchByDate();
		}
		else if (choice == 3){
			handleSearchByContent();
		}

	}

	/**
	 *
	 */
	private void handleSearchByContent() {
		System.out.println("Enter string for content:");
		String content = this.readString();
		//Vector<Post> answer = this._connection.getSearchEngine().searchByContent(content);
		Vector<PostPacket> answer = this._connection.searchByContent(content);
		handleAnswer(answer);
	}

	/**
	 *
	 */
	private void handleSearchByDate() {
		System.out.println("Enter date to search form (format dd/mm/yyyy):");
		String fromDate = this.readString();
		System.out.println("Enter date to search until(format dd/mm/yyyy):");
		String untilDate = this.readString();
		//Vector<Post> answer = this._connection.getSearchEngine().searchByDate(null, null);
		Vector<PostPacket> answer = this._connection.searchByDate(fromDate, untilDate);


		/** stub
		Vector<Post> answer = new Vector<Post>();
		answer.add(new Post(null,null,"my subject", "my content"));
		answer.add(new Post(null,null,"search me", "bla bla bla"));
		**/
		handleAnswer(answer);
	}

	/**
	 *
	 */
	private void handleSearchByAuthor() {
		System.out.println("Enter name of Author:");
		String author = this.readString();
		//Vector<Post> answer = this._connection.getSearchEngine().searchByAuthor(author);
		Vector<PostPacket> answer = this._connection.searchByAuthor(author);
		handleAnswer(answer);
	}

	/**
	 * handling the creation of a Temporary Thread just for watching the
	 * search results that came from the search engine.
	 */
	private void handleAnswer(Vector<PostPacket> answer){
		//ForumThread tthread = new ForumThread(null);
		//tthread.setPosts(answer);
		//this.showItem(tthread);

		ThreadPacket tthread = new ThreadPacket();
		tthread.setPosts(answer);
		this.showItem(tthread);

	}

	/**
	 *
	 */
	private void handlePromoteUser() {
		System.out.println("Please Type A UserName To Promote: ");
		String username = this.readString();
		boolean answer = this._connection.PromoteUser(username);
		if (!answer)
			System.err.println("PROBLEM WITH PROMOTING USER-"+ username);
	}

	private void handleDeleteUser() {
		System.out.println("Please Type A Username To Delete: ");
		String username = this.readString();
		boolean answer = this._connection.deleteUser(username);
		if (answer) {
			System.err.println("user "+username+" is now deleted.");
		}
		else {
			System.err.println("PROBLEM WITH DELETING USER-"+ username);
		}
	}

	/**
	 *
	 */
	private void handleDemoteUser() {
		System.out.println("Please Type A UserName To Demote: ");
		String username = this.readString();
		boolean answer = this._connection.demoteUser(username);
		if (!answer)
			System.err.println("PROBLEM WITH DEMOTING USER-"+ username);

	}

	/**
	 *
	 */
	private void handleDeletePost() {
		boolean success = this._connection.deletePost();
		if (success) {
			System.out.println("Post deleted.");
		}
		else {
			System.out.println("Error - post could not be deleted.");
		}
		this.showItem(this._connection.getCurrentlyViewedItem().getFather());
	}

	/**
	 *
	 */
	private void handleAddANewThread() {
		System.out.println("Type a new Message Subject: ");
		String mSubject = this.readString();
		System.out.println("Type The new Message Text: ");
		String mText = this.readString();
		this._connection.addThread(mSubject,mText);
	}

	/**
	 *
	 */
	private void handleModifiyAMessage() {

		PostPacket viewedPost = (PostPacket) this._connection.getCurrentlyViewedItem();
		String postOwner = viewedPost.getOwner();
		Member loggedMember = (Member) this._connection.getUser();

		if (( (this._connection.getUserRank() > 1) ||
			 (loggedMember.getUserName().equals(postOwner)) )
			 || (this._connection.getUserRank() > 1)) {

				System.out.println("Type a new Message Subject: ");
				String mSubject = this.readString();
				System.out.println("Type The new Message Text: ");
				String mText = this.readString();
				this._connection.updatePost(mSubject, mText);
		}

		else

			System.err.println("You are not permitted to modify this message.");
	}

	/**
	 *
	 */
	private void handleAddMessage() {
		System.out.println("Type a Message Topic: ");
		String mSubject = this.readString();
		System.out.println("Type The Message Text: ");
		String mText = this.readString();
		this._connection.addPost(mSubject, mText);

	}

	/**
	 *
	 */
	private void showRegistrationPage() {
		System.out.println("enter a desired username:");
		String userName = readString();
		System.out.println("enter a desired email:");
		String email = readString();
		System.out.println("enter your desired password:");
		String password = readString();
		if (_connection.registerUser(userName, email, password)) {
			showRegistrationSuccess(userName);
		}
		else {
			showLoginFailed();
		}
	}

	/**
	 *
	 * @param userName
	 */
	private void showRegistrationSuccess(String userName) {
		// TODO Auto-generated method stub
		System.out.println("You are now registered as "+userName);
	}

	/**
	 * there is a tricky thing about topics: a topic's descendant can be another topic or a thread.
	 * this makes some datatype problems. what i did is create a method "showItem" which receives any item
	 * but behaves differently with Topic and with Thread instances. maybe it's because i'm influenced by ML...
	 * tell me if you have other ideas. anyhow, it doesn't matter so much because in the next iteration we will
	 * replace all this with a GUI...
	 * @param topic
	 */
	private void showTopic(TopicPacket topic) {

		Vector<String> subItems = topic.getSubItems();
		for (int i=0; i< subItems.size(); i++) {
			System.out.println("("+(i+1)+") " + subItems.elementAt(i));
		}
	}

	/**
	 * see above...
	 * @param thread
	 */
	private void showThread(ThreadPacket thread) {
		printPosts(thread.getPosts());
	}

	/**
	 * print the posts (title+content) by order on the screen
	 * @param posts
	 */
	private void printPosts(Vector<PostPacket> posts) {
		for (int i=0; i< posts.size(); i++){
			System.out.println("("+(i+1)+")");
			showPost(posts.get(i));
		}
	}


	private void showPost(PostPacket post) {
		if (post != null) {
			System.out.println("****************************"+ post.getSubject() +"******************************************");
			System.out.println("****************************"+ "by "+post.getOwner() +"******************************************");
			//System.out.println("****************************"+ "by "+post.getDate() +"******************************************");
			System.out.println(post.getContent());
			System.out.println("******************************************************************************************");
			System.out.println();
		}
	}


	private void showLoginPage(){

		System.out.println("enter username:");
		String userName = readString();
		System.out.println("enter password:");
		String password = readString();
		if (_connection.login(userName, password)) {
			showLoginSuccess(userName);
		}
		else {
			showLoginFailed();
		}
	}


	/**
	 * read a number from the keyboard
	 * @return
	 */
	private int readNumber() {
		// TODO Auto-generated method stub
		in = new Scanner(System.in);

	    // Reads a single number from the console
		// and stores into name variable
	   int num = in.nextInt();
	   return num;
	}

	/**
	 * read a string from the keyboard
	 * @return
	 */
	private String readString() {
		// TODO Auto-generated method stub
		in = new Scanner(System.in);

	       // Reads a single line from the console
	       // and stores into name variable
	       String line = in.nextLine();
	       return line;
	}


	public void connect(String hostname, int port) {
		try {
			this._connection.connect(hostname, port);
		} catch (UnknownHostException e) {
			// TODO Auto-generated catch block
			System.out.println(e.getMessage());
		} catch (IOException e) {
			// TODO Auto-generated catch block
			System.out.println(e.getMessage());
		}

	}
}
